package com.jianguozh.difs.framework.utils;

import cn.hutool.core.util.StrUtil;
import com.jianguozh.difs.framework.security.AuthenticatedUser;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;

/**
 * token工具类
 *
 * @author hanrs
 * @email 4076130@qq.com
 * @since 2022/3/14 15:25
 */
public class TokenUtils {

    private static final String SECRET_KEY = "MCl25sK9N70cQ";
    private static final Long SECRET_EXPIRATION = 60 * 60 * 8L; //8 hours
    private static final String CLAIM_KEY_USER_ID = "id";
    private static final String CLAIM_KEY_NICK_NAME = "name";
    private static final String CLAIM_KEY_AVATAR = "avatar";
    private static final String CLAIM_KEY_AUTHORITIES = "authorities";
    private static final String CLAIM_KEY_ISSUE_CLIENT_ID = "issueClientId";
    private static final String CLAIM_KEY_ORG = "org";
    private static final String CLAIM_KEY_ORG_ID = "orgId";
    private static final String CLAIM_KEY_ORG_DEFAULT = "orgDefault";
    private static final String CLAIM_KEY_STATUS = "stauts";
    private static final String CLAIM_KEY_PWD_INITED = "pwdInited";

    public static final String AUTHORIZATION_HEADER = "Authorization";
    public static final String TOKEN_PREFIX = "Bearer ";
    public static final String ACCESS_TOKEN = "accessToken";

    /**
     * 生产token
     *
     * @param authenticatedUser
     * @return
     */
    public static String createToken(AuthenticatedUser authenticatedUser) {

        long now = (new Date()).getTime();
        Date validity = new Date(now + SECRET_EXPIRATION * 1000L);

        Claims claims = Jwts.claims().setSubject(authenticatedUser.getUsername());
        claims.put(CLAIM_KEY_USER_ID, authenticatedUser.getId());
        claims.put(CLAIM_KEY_NICK_NAME, authenticatedUser.getName());
        claims.put(CLAIM_KEY_AVATAR, authenticatedUser.getAvatar());
        claims.put(CLAIM_KEY_ISSUE_CLIENT_ID, authenticatedUser.getIssueClientId());
        claims.put(CLAIM_KEY_ORG, authenticatedUser.getOrg());
        claims.put(CLAIM_KEY_ORG_ID, authenticatedUser.getOrgId());
        claims.put(CLAIM_KEY_ORG_DEFAULT, authenticatedUser.getOrgDefault());
        claims.put(CLAIM_KEY_STATUS, authenticatedUser.getStatus());
        claims.put(CLAIM_KEY_PWD_INITED, authenticatedUser.getPwdInited());

        Collection<? extends GrantedAuthority> authorities = authenticatedUser.getAuthorities();
        List<String> list = new ArrayList<>(authorities.size());
        authorities.forEach(authority -> {
            list.add(authority.toString());
        });
        String strAuthorities = String.join(",", list);
        claims.put(CLAIM_KEY_AUTHORITIES, strAuthorities);

        return Jwts.builder().setClaims(claims).setExpiration(validity).signWith(SignatureAlgorithm.HS256, SECRET_KEY)
                .compact();

    }


    /**
     * 解析token,生成AuthorizedUser
     *
     * @param token
     * @return
     */
    public static AuthenticatedUser parseAuthorizedUser(String token) {

        Claims claims = Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody();
        List<GrantedAuthority> authorities = AuthorityUtils
                .commaSeparatedStringToAuthorityList((String) claims.get(CLAIM_KEY_AUTHORITIES));

        AuthenticatedUser principal = new AuthenticatedUser();
        principal.setUsername(claims.getSubject());
        principal.setId((String) claims.get(CLAIM_KEY_USER_ID));
        principal.setName((String) claims.get(CLAIM_KEY_NICK_NAME));
        principal.setAvatar((String) claims.get(CLAIM_KEY_AVATAR));
        principal.setAuthorities(authorities);
        principal.setIssueClientId((String) claims.get(CLAIM_KEY_ISSUE_CLIENT_ID));
        principal.setOrg((String) claims.get(CLAIM_KEY_ORG));
        principal.setOrgId((String) claims.get(CLAIM_KEY_ORG_ID));
        principal.setOrgDefault((Boolean) claims.get(CLAIM_KEY_ORG_DEFAULT));
        principal.setStatus((Boolean) claims.get(CLAIM_KEY_STATUS));
        principal.setPwdInited((Boolean) claims.get(CLAIM_KEY_PWD_INITED));

        return principal;
    }


    /**
     * token 校验
     *
     * @param token
     */
    public static void verifyToken(String token) {
        Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token);
    }

    /**
     * 从request请求中解析token字符串
     *
     * @param request
     * @return
     */
    public static String parseToken(HttpServletRequest request) {
        String bearerToken = request.getHeader(AUTHORIZATION_HEADER);
        if (StrUtil.isNotBlank(bearerToken) && bearerToken.startsWith(TOKEN_PREFIX)) {
            return bearerToken.substring(7);
        }
        String accessToken = request.getParameter(ACCESS_TOKEN);
        if (StrUtil.isNotBlank(accessToken)) {
            return accessToken;
        }
        return null;
    }


}
